/*
 * Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package java.lang;

import java.io.*;
import java.lang.reflect.Executable;
import java.lang.annotation.Annotation;
import java.security.AccessControlContext;
import java.util.Properties;
import java.util.PropertyPermission;
import java.util.StringTokenizer;
import java.util.Map;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.AllPermission;
import java.nio.channels.Channel;
import java.nio.channels.spi.SelectorProvider;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;
import sun.reflect.annotation.AnnotationType;

/**
 * {@code System} 类包含几个有用的类字段和方法。它不能被实例化。
 *
 * <p>{@code System} 类提供的功能包括标准输入、标准输出和错误输出流；
 * 访问外部定义的属性和环境变量；加载文件和库的方法；以及快速复制
 * 数组一部分的实用方法。
 *
 * @author  unascribed
 * @since   JDK1.0
 */
public final class System {

    /* register the natives via the static initializer.
     *
     * VM will invoke the initializeSystemClass method to complete
     * the initialization for this class separated from clinit.
     * Note that to use properties set by the VM, see the constraints
     * described in the initializeSystemClass method.
     */
    private static native void registerNatives();
    static {
        registerNatives();
    }

    /** Don't let anyone instantiate this class */
    private System() {
    }

    /**
     * "标准"输入流。此流已经打开并准备好提供输入数据。
     * 通常此流对应于键盘输入或由主机环境或用户指定的其他输入源。
     */
    public final static InputStream in = null;

    /**
     * "标准"输出流。此流已经打开并准备好接受输出数据。
     * 通常此流对应于显示输出或由主机环境或用户指定的其他输出目标。
     * <p>
     * 对于简单的独立Java应用程序，写入一行输出数据的典型方式是：
     * <blockquote><pre>
     *     System.out.println(data)
     * </pre></blockquote>
     * <p>
     * 参见 {@code PrintStream} 类中的 {@code println} 方法。
     *
     * @see     java.io.PrintStream#println()
     * @see     java.io.PrintStream#println(boolean)
     * @see     java.io.PrintStream#println(char)
     * @see     java.io.PrintStream#println(char[])
     * @see     java.io.PrintStream#println(double)
     * @see     java.io.PrintStream#println(float)
     * @see     java.io.PrintStream#println(int)
     * @see     java.io.PrintStream#println(long)
     * @see     java.io.PrintStream#println(java.lang.Object)
     * @see     java.io.PrintStream#println(java.lang.String)
     */
    public final static PrintStream out = null;

    /**
     * "标准"错误输出流。此流已经打开并准备好接受输出数据。
     * <p>
     * 通常此流对应于显示输出或由主机环境或用户指定的其他输出目标。
     * 按照惯例，此输出流用于显示错误消息或其他应该立即引起用户注意的信息，
     * 即使主要输出流（变量 {@code out} 的值）已被重定向到文件或其他
     * 通常不被持续监控的目标。
     */
    public final static PrintStream err = null;

    /* The security manager for the system.
     */
    private static volatile SecurityManager security = null;

    /**
     * 重新分配"标准"输入流。
     *
     * <p>首先，如果存在安全管理器，将使用 {@code RuntimePermission("setIO")} 权限
     * 调用其 {@code checkPermission} 方法，以查看是否允许重新分配"标准"输入流。
     * <p>
     *
     * @param in 新的标准输入流。
     *
     * @throws SecurityException
     *        如果存在安全管理器且其 {@code checkPermission} 方法不允许
     *        重新分配标准输入流。
     *
     * @see SecurityManager#checkPermission
     * @see java.lang.RuntimePermission
     *
     * @since   JDK1.1
     */
    public static void setIn(InputStream in) {
        checkIO();
        setIn0(in);
    }

    /**
     * 重新分配"标准"输出流。
     *
     * <p>首先，如果存在安全管理器，将使用 {@code RuntimePermission("setIO")} 权限
     * 调用其 {@code checkPermission} 方法，以查看是否允许重新分配"标准"输出流。
     *
     * @param out 新的标准输出流
     *
     * @throws SecurityException
     *        如果存在安全管理器且其 {@code checkPermission} 方法不允许
     *        重新分配标准输出流。
     *
     * @see SecurityManager#checkPermission
     * @see java.lang.RuntimePermission
     *
     * @since   JDK1.1
     */
    public static void setOut(PrintStream out) {
        checkIO();
        setOut0(out);
    }

    /**
     * 重新分配"标准"错误输出流。
     *
     * <p>首先，如果存在安全管理器，将使用 {@code RuntimePermission("setIO")} 权限
     * 调用其 {@code checkPermission} 方法，以查看是否允许重新分配"标准"错误输出流。
     *
     * @param err 新的标准错误输出流。
     *
     * @throws SecurityException
     *        如果存在安全管理器且其 {@code checkPermission} 方法不允许
     *        重新分配标准错误输出流。
     *
     * @see SecurityManager#checkPermission
     * @see java.lang.RuntimePermission
     *
     * @since   JDK1.1
     */
    public static void setErr(PrintStream err) {
        checkIO();
        setErr0(err);
    }

    private static volatile Console cons = null;
    /**
     * 返回与当前Java虚拟机关联的唯一 {@link java.io.Console Console} 对象（如果有）。
     *
     * @return  系统控制台（如果有），否则返回 <tt>null</tt>。
     *
     * @since   1.6
     */
    /**
     * 返回与当前Java虚拟机关联的唯一 {@link java.io.Console Console} 对象（如果有）。
     *
     * @return  系统控制台（如果有），否则返回 <tt>null</tt>。
     *
     * @since   1.6
     */
     public static Console console() {
         if (cons == null) {
             synchronized (System.class) {
                 cons = sun.misc.SharedSecrets.getJavaIOAccess().console();
             }
         }
         return cons;
     }

    /**
     * 返回从创建此Java虚拟机的实体继承的通道。
     *
     * <p> 此方法返回通过调用系统范围默认
     * {@link java.nio.channels.spi.SelectorProvider} 对象的
     * {@link java.nio.channels.spi.SelectorProvider#inheritedChannel
     * inheritedChannel} 方法获得的通道。</p>
     *
     * <p> 除了在 {@link java.nio.channels.spi.SelectorProvider#inheritedChannel
     * inheritedChannel} 中描述的面向网络的通道外，此方法将来可能返回其他类型的通道。
     *
     * @return  继承的通道（如果有），否则返回 {@code null}。
     *
     * @throws  IOException
     *          如果发生I/O错误
     *
     * @throws  SecurityException
     *          如果存在安全管理器且不允许访问通道。
     *
     * @since 1.5
     */
    public static Channel inheritedChannel() throws IOException {
        return SelectorProvider.provider().inheritedChannel();
    }

    private static void checkIO() {
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("setIO"));
        }
    }

    private static native void setIn0(InputStream in);
    private static native void setOut0(PrintStream out);
    private static native void setErr0(PrintStream err);

    /**
     * 设置系统安全管理器。
     *
     * <p> 如果已经安装了安全管理器，此方法首先使用
     * {@code RuntimePermission("setSecurityManager")} 权限调用安全管理器的
     * {@code checkPermission} 方法，以确保可以替换现有的安全管理器。
     * 这可能导致抛出 {@code SecurityException}。
     *
     * <p> 否则，参数将被确立为当前的安全管理器。如果参数为 {@code null}
     * 且没有建立安全管理器，则不采取任何操作，方法简单返回。
     *
     * @param      s   安全管理器。
     * @exception  SecurityException  如果安全管理器已经设置且其
     *             {@code checkPermission} 方法不允许被替换。
     * @see #getSecurityManager
     * @see SecurityManager#checkPermission
     * @see java.lang.RuntimePermission
     */
    public static
    void setSecurityManager(final SecurityManager s) {
        try {
            s.checkPackageAccess("java.lang");
        } catch (Exception e) {
            // no-op
        }
        setSecurityManager0(s);
    }

    private static synchronized
    void setSecurityManager0(final SecurityManager s) {
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            // ask the currently installed security manager if we
            // can replace it.
            sm.checkPermission(new RuntimePermission
                                     ("setSecurityManager"));
        }

        if ((s != null) && (s.getClass().getClassLoader() != null)) {
            // New security manager class is not on bootstrap classpath.
            // Cause policy to get initialized before we install the new
            // security manager, in order to prevent infinite loops when
            // trying to initialize the policy (which usually involves
            // accessing some security and/or system properties, which in turn
            // calls the installed security manager's checkPermission method
            // which will loop infinitely if there is a non-system class
            // (in this case: the new security manager class) on the stack).
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    s.getClass().getProtectionDomain().implies
                        (SecurityConstants.ALL_PERMISSION);
                    return null;
                }
            });
        }

        security = s;
    }

    /**
     * 获取系统安全接口。
     *
     * @return  如果已经为当前应用程序建立了安全管理器，则返回该安全管理器；
     *          否则返回 {@code null}。
     * @see     #setSecurityManager
     */
    public static SecurityManager getSecurityManager() {
        return security;
    }

    /**
     * 返回当前时间（以毫秒为单位）。注意，虽然返回值的时间单位是毫秒，
     * 但值的粒度取决于底层操作系统，可能更大。例如，许多操作系统
     * 以十毫秒为单位测量时间。
     *
     * <p> 有关"计算机时间"和协调世界时(UTC)之间可能出现的细微差异的讨论，
     * 请参见 {@code Date} 类的描述。
     *
     * @return  当前时间与1970年1月1日午夜UTC之间的差值（以毫秒为单位）。
     * @see     java.util.Date
     */
    public static native long currentTimeMillis();

    /**
     * 返回正在运行的Java虚拟机的高分辨率时间源的当前值（以纳秒为单位）。
     *
     * <p>此方法只能用于测量经过的时间，与系统或挂钟时间的任何其他概念无关。
     * 返回的值表示自某个固定但任意的<i>起始</i>时间以来的纳秒数
     * （可能在将来，因此值可能为负）。Java虚拟机实例中此方法的所有调用
     * 都使用相同的起始时间；其他虚拟机实例可能使用不同的起始时间。
     *
     * <p>此方法提供纳秒精度，但不一定提供纳秒分辨率（即值更改的频率）
     * - 除了分辨率至少与 {@link #currentTimeMillis()} 一样好之外，
     * 不做任何保证。
     *
     * <p>跨越大约292年（2<sup>63</sup>纳秒）以上的连续调用之间的差异
     * 由于数值溢出将无法正确计算经过的时间。
     *
     * <p>此方法返回的值只有在计算在同一Java虚拟机实例中获得的
     * 两个此类值之间的差异时才有意义。
     *
     * <p> 例如，要测量某些代码执行需要多长时间：
     *  <pre> {@code
     * long startTime = System.nanoTime();
     * // ... 被测量的代码 ...
     * long estimatedTime = System.nanoTime() - startTime;}</pre>
     *
     * <p>要比较两个nanoTime值
     *  <pre> {@code
     * long t0 = System.nanoTime();
     * ...
     * long t1 = System.nanoTime();}</pre>
     *
     * 应该使用 {@code t1 - t0 < 0}，而不是 {@code t1 < t0}，
     * 因为可能存在数值溢出。
     *
     * @return 正在运行的Java虚拟机的高分辨率时间源的当前值（以纳秒为单位）
     * @since 1.5
     */
    public static native long nanoTime();

    /**
     * 从指定的源数组复制数组，从指定位置开始，到目标数组的指定位置。
     * 数组组件的子序列从 {@code src} 引用的源数组复制到 {@code dest} 引用的目标数组。
     * 复制的组件数等于 {@code length} 参数。源数组中位置 {@code srcPos} 到
     * {@code srcPos+length-1} 的组件分别复制到目标数组的位置 {@code destPos} 到
     * {@code destPos+length-1}。
     * <p>
     * 如果 {@code src} 和 {@code dest} 参数引用同一个数组对象，则执行复制时，
     * 就像首先将位置 {@code srcPos} 到 {@code srcPos+length-1} 的组件复制到
     * 具有 {@code length} 个组件的临时数组，然后将临时数组的内容复制到目标数组的
     * 位置 {@code destPos} 到 {@code destPos+length-1}。
     * <p>
     * 如果 {@code dest} 为 {@code null}，则抛出 {@code NullPointerException}。
     * <p>
     * 如果 {@code src} 为 {@code null}，则抛出 {@code NullPointerException}，
     * 且目标数组不被修改。
     * <p>
     * 否则，如果以下任何一项为真，则抛出 {@code ArrayStoreException}，
     * 且目标数组不被修改：
     * <ul>
     * <li>{@code src} 参数引用的对象不是数组。
     * <li>{@code dest} 参数引用的对象不是数组。
     * <li>{@code src} 参数和 {@code dest} 参数引用的数组的组件类型是不同的基本类型。
     * <li>{@code src} 参数引用具有基本组件类型的数组，而 {@code dest} 参数引用
     *     具有引用组件类型的数组。
     * <li>{@code src} 参数引用具有引用组件类型的数组，而 {@code dest} 参数引用
     *     具有基本组件类型的数组。
     * </ul>
     * <p>
     * 否则，如果以下任何一项为真，则抛出 {@code IndexOutOfBoundsException}，
     * 且目标数组不被修改：
     * <ul>
     * <li>{@code srcPos} 参数为负。
     * <li>{@code destPos} 参数为负。
     * <li>{@code length} 参数为负。
     * <li>{@code srcPos+length} 大于 {@code src.length}（源数组的长度）。
     * <li>{@code destPos+length} 大于 {@code dest.length}（目标数组的长度）。
     * </ul>
     * <p>
     * 否则，如果源数组中位置 {@code srcPos} 到 {@code srcPos+length-1} 的任何实际组件
     * 无法通过赋值转换转换为目标数组的组件类型，则抛出 {@code ArrayStoreException}。
     * 在这种情况下，设 <b><i>k</i></b> 为小于length的最小非负整数，使得
     * {@code src[srcPos+}<i>k</i>{@code ]} 无法转换为目标数组的组件类型；
     * 当抛出异常时，位置 {@code srcPos} 到 {@code srcPos+}<i>k</i>{@code -1}
     * 的源数组组件将已经复制到目标数组位置 {@code destPos} 到
     * {@code destPos+}<i>k</i>{@code -1}，目标数组的其他位置不会被修改。
     * （由于已列举的限制，此段落实际上仅适用于两个数组都具有引用类型组件类型的情况。）
     *
     * @param      src      源数组。
     * @param      srcPos   源数组中的起始位置。
     * @param      dest     目标数组。
     * @param      destPos  目标数据中的起始位置。
     * @param      length   要复制的数组元素数。
     * @exception  IndexOutOfBoundsException  如果复制会导致访问数组边界外的数据。
     * @exception  ArrayStoreException  如果 {@code src} 数组中的元素由于类型不匹配
     *               而无法存储到 {@code dest} 数组中。
     * @exception  NullPointerException 如果 {@code src} 或 {@code dest} 为 {@code null}。
     */
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

    /**
     * 返回给定对象的哈希码，与默认方法 hashCode() 返回的哈希码相同，
     * 无论给定对象的类是否重写了 hashCode()。
     * null引用的哈希码为零。
     *
     * @param x 要计算哈希码的对象
     * @return  哈希码
     * @since   JDK1.1
     */
    public static native int identityHashCode(Object x);

    /**
     * 系统属性。保证定义以下属性：
     * <dl>
     * <dt>java.version         <dd>Java版本号
     * <dt>java.vendor          <dd>Java供应商特定字符串
     * <dt>java.vendor.url      <dd>Java供应商URL
     * <dt>java.home            <dd>Java安装目录
     * <dt>java.class.version   <dd>Java类版本号
     * <dt>java.class.path      <dd>Java类路径
     * <dt>os.name              <dd>操作系统名称
     * <dt>os.arch              <dd>操作系统架构
     * <dt>os.version           <dd>操作系统版本
     * <dt>file.separator       <dd>文件分隔符（Unix上为"/"）
     * <dt>path.separator       <dd>路径分隔符（Unix上为":"）
     * <dt>line.separator       <dd>行分隔符（Unix上为"\n"）
     * <dt>user.name            <dd>用户账户名
     * <dt>user.home            <dd>用户主目录
     * <dt>user.dir             <dd>用户当前工作目录
     * </dl>
     */

    private static Properties props;
    private static native Properties initProperties(Properties props);

    /**
     * 确定当前的系统属性。
     * <p>
     * 首先，如果存在安全管理器，将不带参数地调用其
     * <code>checkPropertiesAccess</code> 方法。这可能导致安全异常。
     * <p>
     * 供 {@link #getProperty(String)} 方法使用的当前系统属性集
     * 作为 <code>Properties</code> 对象返回。如果当前没有系统属性集，
     * 则首先创建并初始化一个系统属性集。此系统属性集始终包含
     * 以下键的值：
     * <table summary="显示属性键和关联值">
     * <tr><th>键</th>
     *     <th>关联值的描述</th></tr>
     * <tr><td><code>java.version</code></td>
     *     <td>Java运行时环境版本</td></tr>
     * <tr><td><code>java.vendor</code></td>
     *     <td>Java运行时环境供应商</td></tr>
     * <tr><td><code>java.vendor.url</code></td>
     *     <td>Java供应商URL</td></tr>
     * <tr><td><code>java.home</code></td>
     *     <td>Java安装目录</td></tr>
     * <tr><td><code>java.vm.specification.version</code></td>
     *     <td>Java虚拟机规范版本</td></tr>
     * <tr><td><code>java.specification.maintenance.version</code></td>
     *     <td>Java运行时环境规范维护版本，可解释为正整数
     *     <em>（可选，见下文）</em></td></tr>
     * <tr><td><code>java.vm.specification.vendor</code></td>
     *     <td>Java虚拟机规范供应商</td></tr>
     * <tr><td><code>java.vm.specification.name</code></td>
     *     <td>Java虚拟机规范名称</td></tr>
     * <tr><td><code>java.vm.version</code></td>
     *     <td>Java虚拟机实现版本</td></tr>
     * <tr><td><code>java.vm.vendor</code></td>
     *     <td>Java虚拟机实现供应商</td></tr>
     * <tr><td><code>java.vm.name</code></td>
     *     <td>Java虚拟机实现名称</td></tr>
     * <tr><td><code>java.specification.version</code></td>
     *     <td>Java运行时环境规范版本</td></tr>
     * <tr><td><code>java.specification.vendor</code></td>
     *     <td>Java运行时环境规范供应商</td></tr>
     * <tr><td><code>java.specification.name</code></td>
     *     <td>Java运行时环境规范名称</td></tr>
     * <tr><td><code>java.class.version</code></td>
     *     <td>Java类格式版本号</td></tr>
     * <tr><td><code>java.class.path</code></td>
     *     <td>Java类路径</td></tr>
     * <tr><td><code>java.library.path</code></td>
     *     <td>加载库时搜索的路径列表</td></tr>
     * <tr><td><code>java.io.tmpdir</code></td>
     *     <td>默认临时文件路径</td></tr>
     * <tr><td><code>java.compiler</code></td>
     *     <td>要使用的JIT编译器名称</td></tr>
     * <tr><td><code>java.ext.dirs</code></td>
     *     <td>扩展目录的路径
     *         <b>已弃用。</b> <i>此属性及其实现机制
     *            可能在未来版本中被移除。</i> </td></tr>
     * <tr><td><code>os.name</code></td>
     *     <td>操作系统名称</td></tr>
     * <tr><td><code>os.arch</code></td>
     *     <td>操作系统架构</td></tr>
     * <tr><td><code>os.version</code></td>
     *     <td>操作系统版本</td></tr>
     * <tr><td><code>file.separator</code></td>
     *     <td>文件分隔符（UNIX上为"/"）</td></tr>
     * <tr><td><code>path.separator</code></td>
     *     <td>路径分隔符（UNIX上为":"）</td></tr>
     * <tr><td><code>line.separator</code></td>
     *     <td>行分隔符（UNIX上为"\n"）</td></tr>
     * <tr><td><code>user.name</code></td>
     *     <td>用户账户名</td></tr>
     * <tr><td><code>user.home</code></td>
     *     <td>用户主目录</td></tr>
     * <tr><td><code>user.dir</code></td>
     *     <td>用户当前工作目录</td></tr>
     * </table>
     * <p>
     * 如果此运行时在构造时实现的规范经历了<a
     * href="https://jcp.org/en/procedures/jcp2#3.6.4">维护
     * 发布</a>，则定义 {@code java.specification.maintenance.version} 属性。
     * 定义后，其值标识该维护发布。要指示第一个维护发布，
     * 此属性的值为 {@code "1"}，要指示第二个维护发布，
     * 此属性的值为 {@code "2"}，依此类推。
     * <p>
     * 系统属性值中的多个路径由平台的路径分隔符字符分隔。
     * <p>
     * 请注意，即使安全管理器不允许 <code>getProperties</code> 操作，
     * 它也可以选择允许 {@link #getProperty(String)} 操作。
     *
     * @return     系统属性
     * @exception  SecurityException  如果存在安全管理器且其
     *             <code>checkPropertiesAccess</code> 方法不允许访问
     *              系统属性。
     * @see        #setProperties
     * @see        java.lang.SecurityException
     * @see        java.lang.SecurityManager#checkPropertiesAccess()
     * @see        java.util.Properties
     */
    public static Properties getProperties() {
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPropertiesAccess();
        }

        return props;
    }

    /**
     * 返回系统相关的行分隔符字符串。它始终返回相同的值 -
     * {@linkplain #getProperty(String) 系统属性} {@code line.separator} 的初始值。
     *
     * <p>在UNIX系统上，它返回 {@code "\n"}；在Microsoft
     * Windows系统上，它返回 {@code "\r\n"}。
     *
     * @return 系统相关的行分隔符字符串
     * @since 1.7
     */
    public static String lineSeparator() {
        return lineSeparator;
    }

    private static String lineSeparator;

    /**
     * 将系统属性设置为 <code>Properties</code> 参数。
     * <p>
     * 首先，如果存在安全管理器，将不带参数地调用其
     * <code>checkPropertiesAccess</code> 方法。这可能导致安全异常。
     * <p>
     * 参数成为供 {@link #getProperty(String)} 方法使用的当前系统属性集。
     * 如果参数为 <code>null</code>，则忘记当前的系统属性集。
     *
     * @param      props   新的系统属性。
     * @exception  SecurityException  如果存在安全管理器且其
     *             <code>checkPropertiesAccess</code> 方法不允许访问
     *              系统属性。
     * @see        #getProperties
     * @see        java.util.Properties
     * @see        java.lang.SecurityException
     * @see        java.lang.SecurityManager#checkPropertiesAccess()
     */
    public static void setProperties(Properties props) {
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPropertiesAccess();
        }
        if (props == null) {
            props = new Properties();
            initProperties(props);
        }
        System.props = props;
    }

    /**
     * 获取由指定键指示的系统属性。
     * <p>
     * 首先，如果存在安全管理器，将以键作为参数调用其
     * <code>checkPropertyAccess</code> 方法。这可能导致SecurityException。
     * <p>
     * 如果当前没有系统属性集，则首先以与 <code>getProperties</code>
     * 方法相同的方式创建并初始化系统属性集。
     *
     * @param      key   系统属性的名称。
     * @return     系统属性的字符串值，如果没有该键的属性则返回 <code>null</code>。
     *
     * @exception  SecurityException  如果存在安全管理器且其
     *             <code>checkPropertyAccess</code> 方法不允许
     *              访问指定的系统属性。
     * @exception  NullPointerException 如果 <code>key</code> 为
     *             <code>null</code>。
     * @exception  IllegalArgumentException 如果 <code>key</code> 为空。
     * @see        #setProperty
     * @see        java.lang.SecurityException
     * @see        java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
     * @see        java.lang.System#getProperties()
     */
    public static String getProperty(String key) {
        checkKey(key);
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPropertyAccess(key);
        }

        return props.getProperty(key);
    }

    /**
     * 获取由指定键指示的系统属性。
     * <p>
     * 首先，如果存在安全管理器，将以 <code>key</code> 作为参数
     * 调用其 <code>checkPropertyAccess</code> 方法。
     * <p>
     * 如果当前没有系统属性集，则首先以与 <code>getProperties</code>
     * 方法相同的方式创建并初始化系统属性集。
     *
     * @param      key   系统属性的名称。
     * @param      def   默认值。
     * @return     系统属性的字符串值，如果没有该键的属性则返回默认值。
     *
     * @exception  SecurityException  如果存在安全管理器且其
     *             <code>checkPropertyAccess</code> 方法不允许
     *             访问指定的系统属性。
     * @exception  NullPointerException 如果 <code>key</code> 为
     *             <code>null</code>。
     * @exception  IllegalArgumentException 如果 <code>key</code> 为空。
     * @see        #setProperty
     * @see        java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
     * @see        java.lang.System#getProperties()
     */
    public static String getProperty(String key, String def) {
        checkKey(key);
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPropertyAccess(key);
        }

        return props.getProperty(key, def);
    }

    /**
     * 设置由指定键指示的系统属性。
     * <p>
     * 首先，如果存在安全管理器，将使用 <code>PropertyPermission(key, "write")</code>
     * 权限调用其 <code>SecurityManager.checkPermission</code> 方法。
     * 这可能导致抛出SecurityException。如果没有抛出异常，
     * 则将指定属性设置为给定值。
     * <p>
     *
     * @param      key   系统属性的名称。
     * @param      value 系统属性的值。
     * @return     系统属性的先前值，如果没有则返回 <code>null</code>。
     *
     * @exception  SecurityException  如果存在安全管理器且其
     *             <code>checkPermission</code> 方法不允许
     *             设置指定的属性。
     * @exception  NullPointerException 如果 <code>key</code> 或
     *             <code>value</code> 为 <code>null</code>。
     * @exception  IllegalArgumentException 如果 <code>key</code> 为空。
     * @see        #getProperty
     * @see        java.lang.System#getProperty(java.lang.String)
     * @see        java.lang.System#getProperty(java.lang.String, java.lang.String)
     * @see        java.util.PropertyPermission
     * @see        SecurityManager#checkPermission
     * @since      1.2
     */
    public static String setProperty(String key, String value) {
        checkKey(key);
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new PropertyPermission(key,
                SecurityConstants.PROPERTY_WRITE_ACTION));
        }

        return (String) props.setProperty(key, value);
    }

    /**
     * 移除由指定键指示的系统属性。
     * <p>
     * 首先，如果存在安全管理器，将使用 <code>PropertyPermission(key, "write")</code>
     * 权限调用其 <code>SecurityManager.checkPermission</code> 方法。
     * 这可能导致抛出SecurityException。如果没有抛出异常，
     * 则移除指定的属性。
     * <p>
     *
     * @param      key   要移除的系统属性的名称。
     * @return     系统属性的先前字符串值，如果没有该键的属性则返回 <code>null</code>。
     *
     * @exception  SecurityException  如果存在安全管理器且其
     *             <code>checkPropertyAccess</code> 方法不允许
     *              访问指定的系统属性。
     * @exception  NullPointerException 如果 <code>key</code> 为
     *             <code>null</code>。
     * @exception  IllegalArgumentException 如果 <code>key</code> 为空。
     * @see        #getProperty
     * @see        #setProperty
     * @see        java.util.Properties
     * @see        java.lang.SecurityException
     * @see        java.lang.SecurityManager#checkPropertiesAccess()
     * @since 1.5
     */
    public static String clearProperty(String key) {
        checkKey(key);
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new PropertyPermission(key, "write"));
        }

        return (String) props.remove(key);
    }

    private static void checkKey(String key) {
        if (key == null) {
            throw new NullPointerException("key can't be null");
        }
        if (key.equals("")) {
            throw new IllegalArgumentException("key can't be empty");
        }
    }

    /**
     * 获取指定环境变量的值。环境变量是系统相关的外部命名值。
     *
     * <p>如果存在安全管理器，将使用
     * <code>{@link RuntimePermission}("getenv."+name)</code>
     * 权限调用其 {@link SecurityManager#checkPermission checkPermission}
     * 方法。这可能导致抛出 {@link SecurityException}。
     * 如果没有抛出异常，则返回变量 <code>name</code> 的值。
     *
     * <p><a name="EnvironmentVSSystemProperties"><i>系统
     * 属性</i>和<i>环境变量</i></a>在概念上都是名称和值之间的映射。
     * 这两种机制都可以用于向Java进程传递用户定义的信息。
     * 环境变量具有更全局的效果，因为它们对定义它们的进程的所有后代都可见，
     * 而不仅仅是直接的Java子进程。在不同的操作系统上，
     * 它们可能具有微妙不同的语义，例如大小写不敏感。
     * 由于这些原因，环境变量更可能产生意外的副作用。
     * 在可能的情况下，最好使用系统属性。当需要全局效果时，
     * 或当外部系统接口需要环境变量时（例如 <code>PATH</code>），
     * 应该使用环境变量。
     *
     * <p>在UNIX系统上，<code>name</code> 的字母大小写通常是重要的，
     * 而在Microsoft Windows系统上通常不重要。例如，表达式
     * <code>System.getenv("FOO").equals(System.getenv("foo"))</code>
     * 在Microsoft Windows上很可能为true。
     *
     * @param  name 环境变量的名称
     * @return 变量的字符串值，如果变量未在系统环境中定义则返回 <code>null</code>
     * @throws NullPointerException 如果 <code>name</code> 为 <code>null</code>
     * @throws SecurityException
     *         如果存在安全管理器且其
     *         {@link SecurityManager#checkPermission checkPermission}
     *         方法不允许访问环境变量 <code>name</code>
     * @see    #getenv()
     * @see    ProcessBuilder#environment()
     */
    public static String getenv(String name) {
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("getenv."+name));
        }

        return ProcessEnvironment.getenv(name);
    }


    /**
     * 返回当前系统环境的不可修改字符串映射视图。
     * 环境是从父进程传递到子进程的系统相关的名称到值的映射。
     *
     * <p>如果系统不支持环境变量，则返回空映射。
     *
     * <p>返回的映射永远不会包含null键或值。
     * 尝试查询null键或值的存在将抛出 {@link NullPointerException}。
     * 尝试查询不是 {@link String} 类型的键或值的存在
     * 将抛出 {@link ClassCastException}。
     *
     * <p>返回的映射及其集合视图可能不遵守
     * {@link Object#equals} 和 {@link Object#hashCode} 方法的一般约定。
     *
     * <p>返回的映射在所有平台上通常都是大小写敏感的。
     *
     * <p>如果存在安全管理器，将使用
     * <code>{@link RuntimePermission}("getenv.*")</code>
     * 权限调用其 {@link SecurityManager#checkPermission checkPermission}
     * 方法。这可能导致抛出 {@link SecurityException}。
     *
     * <p>当向Java子进程传递信息时，
     * <a href=#EnvironmentVSSystemProperties>系统属性</a>
     * 通常比环境变量更受欢迎。
     *
     * @return 作为变量名到值映射的环境
     * @throws SecurityException
     *         如果存在安全管理器且其
     *         {@link SecurityManager#checkPermission checkPermission}
     *         方法不允许访问进程环境
     * @see    #getenv(String)
     * @see    ProcessBuilder#environment()
     * @since  1.5
     */
    public static java.util.Map<String,String> getenv() {
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("getenv.*"));
        }

        return ProcessEnvironment.getenv();
    }

    /**
     * 终止当前运行的Java虚拟机。参数用作状态码；
     * 按照惯例，非零状态码表示异常终止。
     * <p>
     * 此方法调用 <code>Runtime</code> 类中的 <code>exit</code> 方法。
     * 此方法永远不会正常返回。
     * <p>
     * 调用 <code>System.exit(n)</code> 实际上等效于调用：
     * <blockquote><pre>
     * Runtime.getRuntime().exit(n)
     * </pre></blockquote>
     *
     * @param      status   退出状态。
     * @throws  SecurityException
     *        如果存在安全管理器且其 <code>checkExit</code>
     *        方法不允许以指定状态退出。
     * @see        java.lang.Runtime#exit(int)
     */
    public static void exit(int status) {
        Runtime.getRuntime().exit(status);
    }

    /**
     * 运行垃圾收集器。
     * <p>
     * 调用 <code>gc</code> 方法建议Java虚拟机努力回收未使用的对象，
     * 以便使它们当前占用的内存可供快速重用。
     * 当从方法调用返回控制时，Java虚拟机已尽最大努力
     * 从所有丢弃的对象中回收空间。
     * <p>
     * 调用 <code>System.gc()</code> 实际上等效于调用：
     * <blockquote><pre>
     * Runtime.getRuntime().gc()
     * </pre></blockquote>
     *
     * @see     java.lang.Runtime#gc()
     */
    public static void gc() {
        Runtime.getRuntime().gc();
    }

    /**
     * 运行任何待终结对象的终结方法。
     * <p>
     * 调用此方法建议Java虚拟机努力运行已被发现丢弃但其
     * <code>finalize</code> 方法尚未运行的对象的 <code>finalize</code> 方法。
     * 当从方法调用返回控制时，Java虚拟机已尽最大努力
     * 完成所有未完成的终结。
     * <p>
     * 调用 <code>System.runFinalization()</code> 实际上等效于调用：
     * <blockquote><pre>
     * Runtime.getRuntime().runFinalization()
     * </pre></blockquote>
     *
     * @see     java.lang.Runtime#runFinalization()
     */
    public static void runFinalization() {
        Runtime.getRuntime().runFinalization();
    }

    /**
     * 抛出 {@code UnsupportedOperationException}。
     *
     * <p>调用 {@code System.runFinalizersOnExit()} 实际上等效于调用：
     * <blockquote><pre>
     * Runtime.runFinalizersOnExit()
     * </pre></blockquote>
     *
     * @param value 被忽略
     *
     * @deprecated 此方法最初设计用于启用或禁用在退出时运行终结器。
     * 在退出时运行终结器默认是禁用的。如果启用，则在Java运行时退出之前，
     * 将运行所有尚未自动调用终结器的对象的终结器。这种行为本质上是不安全的。
     * 它可能导致在其他线程同时操作这些对象时对活动对象调用终结器，
     * 从而导致不稳定的行为或死锁。
     *
     * @see java.lang.Runtime#runFinalizersOnExit(boolean)
     * @since JDK1.1
     */
    @Deprecated
    public static void runFinalizersOnExit(boolean value) {
        Runtime.runFinalizersOnExit(value);
    }

    /**
     * 加载由filename参数指定的本机库。filename参数必须是绝对路径名。
     *
     * 如果filename参数在去除任何平台特定的库前缀、路径和文件扩展名后，
     * 指示一个名为（例如）L的库，并且名为L的本机库与VM静态链接，
     * 则调用该库导出的JNI_OnLoad_L函数，而不是尝试加载动态库。
     * 与参数匹配的文件名不必存在于文件系统中。
     * 有关更多详细信息，请参见JNI规范。
     *
     * 否则，filename参数以实现相关的方式映射到本机库映像。
     *
     * <p>
     * 调用 <code>System.load(name)</code> 实际上等效于调用：
     * <blockquote><pre>
     * Runtime.getRuntime().load(name)
     * </pre></blockquote>
     *
     * @param      filename   要加载的文件。
     * @exception  SecurityException  如果存在安全管理器且其
     *             <code>checkLink</code> 方法不允许
     *             加载指定的动态库
     * @exception  UnsatisfiedLinkError  如果filename不是绝对路径名，
     *             本机库未与VM静态链接，或者库无法被主机系统
     *             映射到本机库映像。
     * @exception  NullPointerException 如果 <code>filename</code> 为
     *             <code>null</code>
     * @see        java.lang.Runtime#load(java.lang.String)
     * @see        java.lang.SecurityManager#checkLink(java.lang.String)
     */
    @CallerSensitive
    public static void load(String filename) {
        Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);
    }

    /**
     * 加载由 <code>libname</code> 参数指定的本机库。
     * <code>libname</code> 参数不得包含任何平台特定的前缀、文件扩展名或路径。
     * 如果名为 <code>libname</code> 的本机库与VM静态链接，
     * 则调用该库导出的 JNI_OnLoad_<code>libname</code> 函数。
     * 有关更多详细信息，请参见JNI规范。
     *
     * 否则，libname参数从系统库位置加载，并以实现相关的方式
     * 映射到本机库映像。
     * <p>
     * 调用 <code>System.loadLibrary(name)</code> 实际上等效于调用
     * <blockquote><pre>
     * Runtime.getRuntime().loadLibrary(name)
     * </pre></blockquote>
     *
     * @param      libname   库的名称。
     * @exception  SecurityException  如果存在安全管理器且其
     *             <code>checkLink</code> 方法不允许
     *             加载指定的动态库
     * @exception  UnsatisfiedLinkError 如果libname参数包含文件路径，
     *             本机库未与VM静态链接，或者库无法被主机系统
     *             映射到本机库映像。
     * @exception  NullPointerException 如果 <code>libname</code> 为
     *             <code>null</code>
     * @see        java.lang.Runtime#loadLibrary(java.lang.String)
     * @see        java.lang.SecurityManager#checkLink(java.lang.String)
     */
    @CallerSensitive
    public static void loadLibrary(String libname) {
        Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
    }

    /**
     * 将库名映射为表示本机库的平台特定字符串。
     *
     * @param      libname 库的名称。
     * @return     平台相关的本机库名称。
     * @exception  NullPointerException 如果 <code>libname</code> 为
     *             <code>null</code>
     * @see        java.lang.System#loadLibrary(java.lang.String)
     * @see        java.lang.ClassLoader#findLibrary(java.lang.String)
     * @since      1.2
     */
    public static native String mapLibraryName(String libname);

    /**
     * Create PrintStream for stdout/err based on encoding.
     */
    private static PrintStream newPrintStream(FileOutputStream fos, String enc) {
       if (enc != null) {
            try {
                return new PrintStream(new BufferedOutputStream(fos, 128), true, enc);
            } catch (UnsupportedEncodingException uee) {}
        }
        return new PrintStream(new BufferedOutputStream(fos, 128), true);
    }


    /**
     * Initialize the system class.  Called after thread initialization.
     */
    private static void initializeSystemClass() {

        // VM might invoke JNU_NewStringPlatform() to set those encoding
        // sensitive properties (user.home, user.name, boot.class.path, etc.)
        // during "props" initialization, in which it may need access, via
        // System.getProperty(), to the related system encoding property that
        // have been initialized (put into "props") at early stage of the
        // initialization. So make sure the "props" is available at the
        // very beginning of the initialization and all system properties to
        // be put into it directly.
        props = new Properties();
        initProperties(props);  // initialized by the VM

        // There are certain system configurations that may be controlled by
        // VM options such as the maximum amount of direct memory and
        // Integer cache size used to support the object identity semantics
        // of autoboxing.  Typically, the library will obtain these values
        // from the properties set by the VM.  If the properties are for
        // internal implementation use only, these properties should be
        // removed from the system properties.
        //
        // See java.lang.Integer.IntegerCache and the
        // sun.misc.VM.saveAndRemoveProperties method for example.
        //
        // Save a private copy of the system properties object that
        // can only be accessed by the internal implementation.  Remove
        // certain system properties that are not intended for public access.
        sun.misc.VM.saveAndRemoveProperties(props);


        lineSeparator = props.getProperty("line.separator");
        sun.misc.Version.init();

        FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
        FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
        FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
        setIn0(new BufferedInputStream(fdIn));
        setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding")));
        setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding")));

        // Load the zip library now in order to keep java.util.zip.ZipFile
        // from trying to use itself to load this library later.
        loadLibrary("zip");

        // Setup Java signal handlers for HUP, TERM, and INT (where available).
        Terminator.setup();

        // Initialize any miscellenous operating system settings that need to be
        // set for the class libraries. Currently this is no-op everywhere except
        // for Windows where the process-wide error mode is set before the java.io
        // classes are used.
        sun.misc.VM.initializeOSEnvironment();

        // The main thread is not added to its thread group in the same
        // way as other threads; we must do it ourselves here.
        Thread current = Thread.currentThread();
        current.getThreadGroup().add(current);

        // register shared secrets
        setJavaLangAccess();

        // Subsystems that are invoked during initialization can invoke
        // sun.misc.VM.isBooted() in order to avoid doing things that should
        // wait until the application class loader has been set up.
        // IMPORTANT: Ensure that this remains the last initialization action!
        sun.misc.VM.booted();
    }

    private static void setJavaLangAccess() {
        // Allow privileged classes outside of java.lang
        sun.misc.SharedSecrets.setJavaLangAccess(new sun.misc.JavaLangAccess(){
            public sun.reflect.ConstantPool getConstantPool(Class<?> klass) {
                return klass.getConstantPool();
            }
            public boolean casAnnotationType(Class<?> klass, AnnotationType oldType, AnnotationType newType) {
                return klass.casAnnotationType(oldType, newType);
            }
            public AnnotationType getAnnotationType(Class<?> klass) {
                return klass.getAnnotationType();
            }
            public Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationMap(Class<?> klass) {
                return klass.getDeclaredAnnotationMap();
            }
            public byte[] getRawClassAnnotations(Class<?> klass) {
                return klass.getRawAnnotations();
            }
            public byte[] getRawClassTypeAnnotations(Class<?> klass) {
                return klass.getRawTypeAnnotations();
            }
            public byte[] getRawExecutableTypeAnnotations(Executable executable) {
                return Class.getExecutableTypeAnnotationBytes(executable);
            }
            public <E extends Enum<E>>
                    E[] getEnumConstantsShared(Class<E> klass) {
                return klass.getEnumConstantsShared();
            }
            public void blockedOn(Thread t, Interruptible b) {
                t.blockedOn(b);
            }
            public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) {
                Shutdown.add(slot, registerShutdownInProgress, hook);
            }
            public int getStackTraceDepth(Throwable t) {
                return t.getStackTraceDepth();
            }
            public StackTraceElement getStackTraceElement(Throwable t, int i) {
                return t.getStackTraceElement(i);
            }
            public String newStringUnsafe(char[] chars) {
                return new String(chars, true);
            }
            public Thread newThreadWithAcc(Runnable target, AccessControlContext acc) {
                return new Thread(target, acc);
            }
            public void invokeFinalize(Object o) throws Throwable {
                o.finalize();
            }
        });
    }
}
